package rpg.client;

import java.util.Collections;
import java.util.List;

import rpg.client.model.Position;
import rpg.util.Strings;

public class Instruction {
	private static class Builder {
		private final Type type;

		private final String playerID;
		private String storyID = "";

		private final Position position = Position.VOID;
		private String fromID = "";

		private String description = "";

		public Builder(final String pid, final Type t) {
			super();
			playerID = pid;
			type = t;
		}

		public Instruction build() {
			return new Instruction(this);
		}

		Builder description(final String s) {
			description = s;
			return this;
		}

		Builder fromID(final String s) {
			fromID = s;
			return this;
		}

		Builder storyID(final String s) {
			storyID = s;
			return this;
		}
	}

	public enum Type {
		MOVE_FORWARD(false), NOTHING(false), TURN_RIGHT(false), TURN_LEFT(false), USE_MOVER(
				true), START_CHAT(true), USE_OBJECT(true), WEAR(false), MOVE_NORTH(
				false), MOVE_SOUTH(false), MOVE_WEST(false), MOVE_EAST(false);

		final boolean descriptionFlag;

		Type(final boolean df) {
			descriptionFlag = df;
		}
	}

	public static final List<Instruction> EMPTY_LIST = Collections.emptyList();

	public static final Instruction forward(final String playerID) {
		return new Builder(playerID, Type.MOVE_FORWARD).build();
	}

	public static final Instruction moveDirection(final String playerID,
			final Instruction.Type type) {
		return new Builder(playerID, type).build();
	}

	public static Instruction mover(final String pid, final String moverID,
			final String description) {
		final Builder b = new Builder(pid, Type.USE_MOVER);
		b.fromID(moverID);
		b.description(description);
		return b.build();
	}

	public static final Instruction pass(final String playerID) {
		return new Builder(playerID, Type.NOTHING).build();
	}

	public static Instruction startChat(final String playerID,
			final String storyID, final String id, final String name) {
		final Builder b = new Builder(playerID, Type.START_CHAT);
		b.storyID(storyID);
		b.fromID(id);
		b.description("Talk to " + name);
		return b.build();
	}

	public static final Instruction turnLeft(final String playerID) {
		return new Builder(playerID, Type.TURN_LEFT).build();
	}

	public static final Instruction turnRight(final String playerID) {
		return new Builder(playerID, Type.TURN_RIGHT).build();
	}

	public static Instruction useObject(final String playerID, final String id,
			final String name) {
		final Builder b = new Builder(playerID, Type.USE_OBJECT);
		b.fromID(id);
		b.description("Use " + name);
		return b.build();
	}

	public static Instruction wear(final String playerID,
			final String gameObjectID) {
		final Builder b = new Builder(playerID, Type.WEAR);
		b.fromID(gameObjectID);
		return b.build();
	}

	private final Type type;

	private final String playerID;
	private final Position position;

	private final String fromID;
	private final String description;

	private final String storyID;

	private Instruction(final Builder b) {
		super();
		type = b.type;
		playerID = Strings.requireNonEmpty(b.playerID, "Instruction.playerID");
		storyID = b.storyID;
		position = b.position;
		fromID = b.fromID;
		description = b.description;
	}

	@Override
	public boolean equals(final Object o) {
		if (o == null) {
			return false;
		}
		if (!(o instanceof Instruction)) {
			return false;
		}

		final Instruction i = (Instruction) o;

		if (this.getType() != i.getType()) {
			return false;
		}

		if (!getFromID().equals(i.getFromID())) {
			return false;
		}

		return getPlayerID().equals(i.getPlayerID());
	}

	public String getDescription() {
		return description;
	}

	public String getFromID() {
		return fromID;
	}

	public String getPlayerID() {
		return playerID;
	}

	public Position getPosition() {
		return position;
	}

	public String getStoryID() {
		return storyID;
	}

	public Type getType() {
		return type;
	}

	@Override
	public int hashCode() {
		int hc = type.hashCode();
		hc += getFromID().hashCode();
		hc += getPlayerID().hashCode();
		return hc;
	}

	@Override
	public String toString() {
		if (getType().descriptionFlag) {
			return "Instruction " + getDescription();
		}
		return "Instruction " + getType();
	}
}
